import * as Lab from "@hapi/lab";
import suite from "./suites/interface-suite";

const lab = exports.lab = Lab.script();

// suite.run(lab, { EXPERIMENTAL: true });
suite.run(lab, { EXPERIMENTAL: false });

// import { expect } from "code";
// import * as Lab from "lab";
// import getHelper from "lab-testing";

// const lab = exports.lab = Lab.script();
// const testing = getHelper(lab);
// const group = testing.createExperiment("map-factory");

// import createMapper from "../lib/map-factory";
// import Mapping from "../lib/mapping";
// import Mapper from "../lib/mapper";


// function createSut() {
//   return createMapper({ experimental: true });
// }

// group("basic functionality", () => {

//   lab.test("Can map one field that exists to another", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       }
//     };

//     const map = createSut();

//     map("fieldName").to("field.name");

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("Throws if a null source is provided", done => {

//     const map = createSut();

//     map("fieldName").to("field.name");

//     const throws = function () {

//       map.execute(null);

//     };

//     expect(throws).to.throw();

//     return done();
//   });

//   lab.test("Throws if an undefined source is provided", done => {

//     const map = createSut();

//     map("fieldName").to("field.name");

//     const throws = function () {

//       map.execute(undefined);

//     };

//     expect(throws).to.throw();

//     return done();
//   });

//   lab.test("Can reuse map for different transform", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const source2 = {
//       "fieldName": "name2"
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       }
//     };

//     const expected2 = {
//       "field": {
//         "name": "name2"
//       }
//     };

//     const map = createSut();

//     map("fieldName").to("field.name");

//     const actual = map.execute(source);
//     const actual2 = map.execute(source2);

//     expect(actual).to.equal(expected);
//     expect(actual2).to.equal(expected2);

//     return done();
//   });

//   lab.test("Can map from a source where source name is not formatted as a string", done => {

//     const source = {
//       country: "PL"
//     };

//     const expected = {
//       "country": "PL"
//     };

//     const map = createSut();

//     map("country").to("country");

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("A field that doesn't exists on the source doesn't affect the resulting object", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       }
//     };

//     const map = createSut();

//     map("fieldName").to("field.name");
//     map("fieldId").to("field.name");

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("A field that doesn't exists on the source doesn't affect the resulting object when a pass-through transform is used", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       }
//     };

//     const map = createSut();

//     map("fieldName").to("field.name");
//     map("fieldId").to("field.name", value => value);

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("A null source field throws an error", done => {

//     const map = createSut();

//     const throws = function () {

//       map(null).to("field.name");

//     };

//     expect(throws).to.throw();

//     return done();

//   });

//   lab.test("A null target field throws an error", done => {

//     const map = createSut();

//     const throws = function () {

//       map("fieldName").to(null);

//     };

//     expect(throws).to.throw();

//     return done();

//   });

//   lab.test("The source field is used if no target field is provided", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const map = createSut();

//     map("fieldName");

//     const actual = map.execute(source);

//     expect(actual).to.equal(source);

//     return done();
//   });

//   lab.test("A source field can be mapped multiple times", done => {

//     const source = {
//       "fieldName": "name"
//     };

//     const expected = {
//       "field": "name",
//       "name": "name-long"
//     };

//     const map = createSut();

//     map("fieldName").to("field");
//     map("fieldName").to("name", value => `${value}-long`);

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });
// });

// group("alternate interfaces", () => {

//   lab.test("default function and map() function are logically equivalent", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       }
//     };

//     const map = createSut();
//     const mapper = createSut();

//     map("fieldName").to("field.name");
//     mapper.map("fieldName").to("field.name");

//     const defaultActual = map.execute(source);
//     const functionActual = mapper.execute(source);

//     expect(defaultActual).to.equal(expected);
//     expect(defaultActual).to.equal(functionActual);

//     return done();

//   });

// });

// group("fluent chaining ", () => {

//   lab.test("map() returns a chainable object", done => {

//     const mapper = createSut();

//     const actual = mapper.map("userId");

//     expect(actual).to.not.be.null();
//     expect(actual).to.be.instanceOf(Mapping);

//     return done();

//   });

//   lab.test("to() returns a chainable object", done => {

//     const mapper = createSut();

//     const actual = mapper.map("userId").to("user.id");

//     expect(actual).to.not.be.null();
//     expect(actual).to.be.instanceOf(Mapper);

//     return done();

//   });

//   lab.test("to() with a function returns a chainable object", done => {

//     const mapper = createSut();

//     const actual = mapper.map("userId").to("user.id", () => {
//       return "a";
//     });

//     expect(actual).to.not.be.null();
//     expect(actual).to.be.instanceOf(Mapper);

//     return done();

//   });

//   lab.test("mapper can fluently chain call map() after the map() method", done => {

//     const source = {
//       "userId": 123,
//       "userName": "my name"
//     };

//     const expected = {
//       "userId": 123,
//       "name": "my name"
//     };

//     const mapper = createSut();

//     mapper
//       .map("userId")
//       .map("userName").to("name");

//     const actual = mapper.execute(source);

//     expect(actual).to.equal(expected);

//     return done();

//   });

//   lab.test("mapper can fluently chain call map() after the to() method", done => {

//     const source = {
//       "userId": 123,
//       "userName": "my name"
//     };

//     const expected = {
//       "id": 123,
//       "name": "my name"
//     };

//     const mapper = createSut();

//     mapper
//       .map("userId").to("id")
//       .map("userName").to("name");

//     const actual = mapper.execute(source);

//     expect(actual).to.equal(expected);

//     return done();

//   });

//   lab.test("mapper can fluently chain call execute() after the to() method", done => {

//     const source = {
//       "userId": 123,
//       "userName": "my name"
//     };

//     const expected = {
//       "id": 123,
//       "name": "my name"
//     };

//     const mapper = createSut();

//     const actual = mapper
//       .map("userId").to("id")
//       .map("userName").to("name")
//       .execute(source);

//     expect(actual).to.equal(expected);

//     return done();

//   });

//   lab.test("mapper can fluently chain call execute() after the map() method", done => {

//     const source = {
//       "userId": 123
//     };

//     const expected = {
//       "userId": 123
//     };

//     const mapper = createSut();

//     const actual = mapper
//       .map("userId")
//       .execute(source);

//     expect(actual).to.equal(expected);

//     return done();

//   });

// });

// group("The each() method", () => {

//   lab.test("Can process an array correctly", done => {
//     const source = [{
//       "fieldName": "name1"
//     }, {
//       "fieldName": "name2"
//     }];

//     const expected = [
//       {
//         "field": {
//           "name": "name1"
//         }
//       },
//       {
//         "field": {
//           "name": "name2"
//         }
//       }];

//     const map = createSut();

//     map("fieldName").to("field.name");

//     const actual = map.each(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("An empty array does not cause an error", done => {
//     const source = [];

//     const expected = [];

//     const map = createSut();

//     map("fieldName").to("field.name");

//     const actual = map.each(source);


//     expect(actual).to.equal(expected);

//     return done();

//   });

//   lab.test("Multiple mappers can be used together", done => {
//     const source = {
//       one: [{ value: "a", drop: "me" }, { value: "b", drop: "me" }, { value: "c", drop: "me" }],
//       two: [{ value: "a", drop: "me" }, { value: "b", drop: "me" }, { value: "c", drop: "me" }],
//       three: [{ value: "a", drop: "me" }, { value: "b", drop: "me" }, { value: "c", drop: "me" }]
//     };

//     const expected = {
//       one: [{ newOne: "a" }, { newOne: "b" }, { newOne: "c" }],
//       two: [{ newOne: "a" }, { newOne: "b" }, { newOne: "c" }],
//       three: [{ newOne: "a" }, { newOne: "b" }, { newOne: "c" }]
//     };

//     const mainMapper = createSut();
//     const childMapper = createSut();

//     childMapper
//       .map("value").to("newOne");

//     mainMapper
//       .map("one").to("one", array => childMapper.each(array))
//       .map("two").to("two", array => childMapper.each(array))
//       .map("three").to("three", array => childMapper.each(array));

//     const actual = mainMapper.execute(source);

//     expect(actual).to.equal(expected);

//     return done();

//   });

//   lab.test("A null parameter throws an error", done => {
//     const map = createSut();

//     map("fieldName").to("field.name");

//     const throws = function () {
//       map.each(null);
//     };

//     expect(throws).to.throw();


//     return done();
//   });

//   lab.test("A non-array throws an error", done => {
//     const map = createSut();
//     const source = { "a": "b" };

//     map("fieldName").to("field.name");


//     const throws = function () {
//       map.each(source);
//     };

//     expect(throws).to.throw();

//     return done();
//   });
// });

// group("source and destination", () => {

//   lab.test("Can map fields from a source onto an existing destination object", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const destination = {
//       "existing": "field"
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       },
//       "existing": "field"
//     };

//     const map = createSut();

//     map("fieldName").to("field.name");

//     const actual = map.execute(source, destination);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("Can map a field from source over an existing field on a destination object", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const destination = {
//       "field": {
//         "name": "wrong"
//       }
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       }
//     };

//     const map = createSut();

//     map("fieldName").to("field.name");

//     const actual = map.execute(source, destination);

//     expect(actual).to.equal(expected);

//     return done();
//   });
// });

// group("custom functions", () => {

//   lab.test("Calls a function and alters the resulting object", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "altered"
//       }
//     };

//     const map = createSut();

//     map("fieldName").to("field.name", () => "altered");

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });
// });

// group("multiple selections", () => {

//   lab.test("Can extract multiple selections into a single transform", done => {

//     const source = {
//       "group1": {
//         "name": "A"
//       },
//       "group2": {
//         "name": "B"
//       }
//     };

//     const expected = {
//       "merged": { "names": ["A", "B"] }
//     };

//     const map = createSut();

//     map(["group1", "group2"]).to("merged", (group1, group2) => {
//       return { "names": [group1.name, group2.name] };
//     });

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("Can extract multiple selections into a single transform while allowing simpler mappings to work", done => {

//     const source = {
//       "person": {
//         "name": "joe"
//       },
//       "group1": {
//         "name": "A"
//       },
//       "group2": {
//         "name": "B"
//       }
//     };

//     const expected = {
//       "name": "joe",
//       "merged": { "groups": ["A", "B"] }
//     };

//     const map = createSut();

//     map("person.name").to("name");
//     map(["group1", "group2"]).to("merged", (group1, group2) => {
//       return { "groups": [group1.name, group2.name] };
//     });

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("If multiple selections aren't mapped to a transform and error will occur", done => {

//     const source = {
//       "person": {
//         "name": "joe"
//       },
//       "group1": {
//         "name": "A"
//       },
//       "group2": {
//         "name": "B"
//       }
//     };

//     const map = createSut();

//     map("person.name").to("name");
//     map(["group1", "group2"]).to("merged");

//     const throws = function () {

//       map.execute(source);
//     };

//     expect(throws).to.throw();

//     return done();
//   });
// });

// group("The or() method", () => {

//   lab.test("Maps the first item if it is present", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       }
//     };

//     const map = createSut();

//     map("fieldName").or("noField").to("field.name");

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();

//   });

//   lab.test("to method can use a transform if provided with first item", done => {
//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "altered name1"
//       }
//     };

//     const map = createSut();

//     map("fieldName").or("noField").to("field.name", value => `altered ${value}`);

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("Maps the second item if the first item isn't present", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       }
//     };

//     const map = createSut();

//     map("noField").or("fieldName").to("field.name");

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("Maps the last item in a very long chain", done => {

//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "name1"
//       }
//     };

//     const map = createSut();

//     map("a").or("b").or("c").or("d").or("e").or("fieldName").to("field.name");

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("to method can use a transform if provided with subsequent item", done => {
//     const source = {
//       "fieldName": "name1"
//     };

//     const expected = {
//       "field": {
//         "name": "altered name1"
//       }
//     };

//     const map = createSut();

//     map("noField").or("fieldName").to("field.name", value => `altered ${value}`);

//     const actual = map.execute(source);

//     expect(actual).to.equal(expected);

//     return done();
//   });

//   lab.test("Throws if the initial source field is an array", done => {

//     const map = createSut();


//     const throws = function () {

//       map(["a", "b"]).or("fieldName").to("field.name");

//     };

//     expect(throws).to.throw();

//     done();

//   });

//   lab.test("Throws if and subsequent source field is an array", done => {

//     const map = createSut();

//     const throws = function () {

//       map("fieldName").or(["a", "b"]).to("field.name");

//     };

//     expect(throws).to.throw();

//     done();
//   });

//   lab.test("Throws if source is null", done => {
//     const map = createSut();

//     const throws = function () {

//       map("fieldName").or(null).to("field.name");

//     };

//     expect(throws).to.throw();

//     done();

//   });

//   lab.test("Throws if source is undefined", done => {
//     const map = createSut();

//     const throws = function () {

//       map("fieldName").or(undefined).to("field.name");

//     };

//     expect(throws).to.throw();

//     done();

//   });

// });

// // PORTED TESTS

// group("ported object-mapper tests", () => {
//   lab.test("mapping - map and append full array to existing mapped array", done => {
//     const obj = {
//       thing: [
//         { a: "a1", i: "b1" },
//         { a: "a2", i: "b2" },
//         { a: "a3", i: "b3" }
//       ],
//       thingOther: [
//         { a: "a4", i: "b4" },
//         { a: "a5", i: "b5" },
//         { a: "a6", i: "b6" }
//       ]
//     };

//     const expected = {
//       "thing2": [
//         [
//           { a: "a1", i: "b1" },
//           { a: "a2", i: "b2" },
//           { a: "a3", i: "b3" }
//         ],
//         [
//           { a: "a4", i: "b4" },
//           { a: "a5", i: "b5" },
//           { a: "a6", i: "b6" }
//         ]
//       ]
//     };

//     const map = createSut();

//     map("thing").to("thing2[]+");
//     map("thingOther").to("thing2[]+");

//     const result = map.execute(obj);

//     expect(result).to.equal(expected);
//     return done();
//   });

//   lab.test("map object to another - allow null values", done => {
//     const obj = {
//       "a": 1234,
//       "foo": {
//         "bar": null
//       }
//     };

//     const expected = {
//       foo: {
//         a: 1234
//       },
//       bar: {
//         bar: null
//       }
//     };

//     const map = createSut();

//     map("foo.bar").to("bar.bar?");
//     map("a").to("foo.a");

//     const result = map.execute(obj);

//     expect(result).to.equal(expected);
//     return done();
//   });

//   lab.test("map object to another - with three destinations for same value", done => {
//     const baseObject = {
//       test: 1
//     };

//     const obj = {
//       "foo": {
//         "bar": "baz"
//       }
//     };

//     const expected = {
//       test: 1,
//       bar: {
//         foo: [{
//           baz: "baz",
//           foo: "baz",
//           bar: ["baz"]
//         }]
//       }
//     };

//     const map = createSut();

//     map("foo.bar").to("bar.foo[].baz");
//     map("foo.bar").to("bar.foo[].foo");
//     map("foo.bar").to("bar.foo[].bar[]");


//     const result = map.execute(obj, baseObject);

//     expect(result).to.equal(expected);
//     return done();
//   });

//   lab.test.skip("original constious tests", done => {
//     //    const merge = om.merge;

//     const obj = {
//       "sku": "12345",
//       "upc": "99999912345X",
//       "title": "Test Item",
//       "descriptions": ["Short description", "Long description"],
//       "length": 5,
//       "width": 2,
//       "height": 8,
//       "inventory": {
//         "onHandQty": 0,
//         "replenishQty": null
//       },
//       "price": 100
//     };

//     const mapper = createSut();

//     mapper
//       .map("sku").to("Envelope.Request.Item.SKU")
//       .map("upc").to("Envelope.Request.Item.UPC")
//       .map("title").to("Envelope.Request.Item.ShortTitle")
//       .map("length").to("Envelope.Request.Item.Dimensions.Length")
//       .map("width").to("Envelope.Request.Item.Dimensions.Width")
//       .map("height").to("Envelope.Request.Item.Dimensions.Height")
//       .map("weight").to("Envelope.Request.Item.Weight", () => 10)
//       .map("weightUnits").to("Envelope.Request.Item.WeightUnits", () => null)
//       .map("inventory.onHandQty").to("Envelope.Request.Item.Inventory?")
//       .map("inventory.replenishQty").to("Envelope.Request.Item.RelpenishQuantity?")
//       .map("inventory.isInventoryItem").to("Envelope.Request.Item.OnInventory")
//       .map("price").to("Envelope.Request.Item.Price[].List")
//       .map("price").to("Envelope.Request.Item.Price[].Value")
//       .map("price").to("Test[]")
//       .map("descriptions[0]").to("Envelope.Request.Item.ShortDescription")
//       .map("descriptions[1]").to("Envelope.Request.Item.LongDescription");

//     const map = {
//       "sku": "Envelope.Request.Item.SKU"
//       , "upc": "Envelope.Request.Item.UPC"
//       , "title": "Envelope.Request.Item.ShortTitle"
//       , "length": "Envelope.Request.Item.Dimensions.Length"
//       , "width": "Envelope.Request.Item.Dimensions.Width"
//       , "height": "Envelope.Request.Item.Dimensions.Height"
//       , "weight": [
//         ["Envelope.Request.Item.Weight", null, function () {
//           return 10;
//         }]
//       ]
//       , "weightUnits": [["Envelope.Request.Item.WeightUnits", null, function () {
//         return null;
//       }]]
//       , "inventory.onHandQty": "Envelope.Request.Item.Inventory?"
//       , "inventory.replenishQty": "Envelope.Request.Item.RelpenishQuantity?"
//       , "inventory.isInventoryItem": { key: ["Envelope.Request.Item.OnInventory", null, "YES"] }
//       , "price": ["Envelope.Request.Item.Price[].List", "Envelope.Request.Item.Price[].Value", "Test[]"]
//       , "descriptions[0]": "Envelope.Request.Item.ShortDescription"
//       , "descriptions[1]": "Envelope.Request.Item.LongDescription"
//     };

//     const expected = {
//       Test: [100],
//       Envelope: {
//         Request: {
//           Item: {
//             SKU: "12345",
//             UPC: "99999912345X",
//             ShortTitle: "Test Item",
//             Dimensions: {
//               Length: 5,
//               Width: 2,
//               Height: 8
//             },
//             Weight: 10,
//             Inventory: 0,
//             RelpenishQuantity: null,
//             OnInventory: "YES",
//             Price: [{
//               List: 100,
//               Value: 100
//             }],
//             ShortDescription: "Short description",
//             LongDescription: "Long description"
//           }
//         }
//       }
//     };

//     let result = merge(obj, {}, map);

//     expect(result).to.equal(expected);

//     map.sku = {
//       key: "Envelope.Request.Item.SKU",
//       transform: (val, objFrom, objTo) => {
//         return "over-ridden-sku";
//       }
//     };

//     expected.Envelope.Request.Item.SKU = "over-ridden-sku";

//     result = merge(obj, {}, map);

//     expect(result, "override sku").to.equal(expected);

//     obj.inventory = null;
//     expected.Envelope.Request.Item.Inventory = null;

//     result = merge(obj, {}, map);

//     expect(result, "null inventory").to.equal(expected);

//     return done();
//   });

// });

// // group("array edge case", () => {

// //   lab.test("A deep array maps properly", done => {

// //     const source = {
// //       array: [{ id: 1 }, { id: 2 }, { id: 3 }]
// //     };

// //     const expected = {
// //       array: {
// //         levels: [{ id: 1 }, { id: 2 }, { id: 3 }]
// //       }
// //     };

// //     const map = createSut();

// //     map("array.[].id").to("array.levels.[].id");

// //     const actual = map.execute(source);

// //     expect(actual).to.equal(expected);

// //     return done();

// //   });

// //   lab.test("A null source should not do funky stuff when an array is in the mix", done => {

// //     const source = {
// //       array: null
// //     };

// //     const expected = {
// //     };

// //     const map = createSut();

// //     map(["array.[].id"]).to("array.levels.[].id", value => value);

// //     const actual = map.execute(source);

// //     expect(actual).to.equal(expected);

// //     return done();

// //   });

// //   lab.test("A undefined array in source should not do funky stuff when an array is in the mix", done => {

// //     const source = {
// //     };

// //     const expected = {
// //     };

// //     const map = createSut();

// //     map(["array.[].id"]).to("array.levels.[].id", value => value);

// //     const actual = map.execute(source);

// //     expect(actual).to.equal(expected);

// //     return done();

// //   });

// //   lab.test("A undefined array in source should not do funky stuff when an array is in the mix", done => {

// //     const source = {
// //       "something": {
// //         "array": undefined,
// //         "id": "123"
// //       }
// //     };

// //     const expected = {
// //     };

// //     const map = createSut();

// //     map(["something.array.[].id"]).to("something.array.levels.[].id", value => value);

// //     const actual = map.execute(source);

// //     expect(actual).to.equal(expected);

// //     return done();

// //   });

// // });
